
#include <GridServer.h>
#include "BehaviorGridServer.h"
#include "gridprotocol.pb.h"
#include <MasterTask.h>
#include "GridSlaveTaskReturnOne.h"
#include "GridSlaveTaskRandomNumbers.h"
#include <stdlib.h>
#include <iostream>
#include <string>
//#include <boost/bind.hpp>
//#include <boost/thread.hpp>
#include <Log.h>

//declare namespaces
using namespace Network;
using namespace MasterWorkerFramework;

int main()
{
		std::string input;
		std::string ip;
		GridMasterTask* master =NULL;
		PrintLog("Server IP:");

		std::getline(std::cin, ip);

		PrintLog("Server starting up...");
		
		//initialize boost ioservice
		asio::io_service io_service;

		//initialize GridServer with request and response message type with as args the service, the current workstation ip, 
		//the port to which received or emit messages, the timeout for checkalive of available connections 
		GridServer<gridprotocol::Request,gridprotocol::Response> server(io_service,ip,4050,2);

		//initialize the BehaviorGridServer implementation
		BehaviorGridServer* behaviorServer = new BehaviorGridServer();
		
		//start the server
		server.Start(behaviorServer);

		//In order to use a shell, start a thread
		boost::thread t(boost::bind(&boost::asio::io_service::run, &io_service));


		PrintLog("Server running");

		
		while (std::getline(std::cin, input))
		{
				if (input=="avc")
				{
					server.GetConnectionManager()->PrintAvailableConnections();
				}
				
				if (input=="execMixte")
				 {
						//Create the slaves tasks
					 	GridSlaveTaskRandomNumber* s1 = new GridSlaveTaskRandomNumber("1");
						GridSlaveTaskReturnOne* s2 = new GridSlaveTaskReturnOne("2");
						GridSlaveTaskReturnOne* s3 = new GridSlaveTaskReturnOne("3");
						GridSlaveTaskReturnOne* s4 = new GridSlaveTaskReturnOne("4");
						GridSlaveTaskReturnOne* s5 = new GridSlaveTaskReturnOne("5");
						GridSlaveTaskRandomNumber* s6 = new GridSlaveTaskRandomNumber("6");
						GridSlaveTaskReturnOne* s7 = new GridSlaveTaskReturnOne("7");
						GridSlaveTaskRandomNumber* s8 = new GridSlaveTaskRandomNumber("8");
						GridSlaveTaskReturnOne* s9 = new GridSlaveTaskReturnOne("9");
						GridSlaveTaskReturnOne* s10 = new GridSlaveTaskReturnOne("10");
						GridSlaveTaskRandomNumber* s11 = new GridSlaveTaskRandomNumber("11");
						GridSlaveTaskRandomNumber* s12 = new GridSlaveTaskRandomNumber("12");
						GridSlaveTaskReturnOne* s13 = new GridSlaveTaskReturnOne("13");
						GridSlaveTaskRandomNumber* s14 = new GridSlaveTaskRandomNumber("14");
						GridSlaveTaskReturnOne* s15 = new GridSlaveTaskReturnOne("15");
						GridSlaveTaskReturnOne* s16 = new GridSlaveTaskReturnOne("16");

						//bind them (or not...)
						//binding mean loading one execution args with the product of another.
						//This define the dependencies within a task graph
						//operator <= set the number of iteration (default 1)
						s5->BindTaskCompleted(s2)<=500000; 
						s2->BindTaskCompleted(s3)<=500000;
						s4->BindTaskCompleted(s9)<=500000; 
						s3->BindTaskCompleted(s7)<=500000;
						s6->BindTaskCompleted(s2)<=500000;
						s1->BindTaskCompleted(s3)<=500000;

						s9->BindTaskCompleted(s12)<=500000;
						s10->BindTaskCompleted(s9)<=500000;
						s11->BindTaskCompleted(s4)<=500000;
						s8->BindTaskCompleted(s4)<=500000;

						s13->BindTaskCompleted(s14)<=500000;
						s14->BindTaskCompleted(s15)<=500000;
						s16->BindTaskCompleted(s15)<=500000;

						//create a master task to act as a container
						master = new GridMasterTask();
						master->AddTask(s1);
						master->AddTask(s2);
						master->AddTask(s3);
						master->AddTask(s4);
						master->AddTask(s5);
						master->AddTask(s6);
						master->AddTask(s7);
						master->AddTask(s8);
						master->AddTask(s9);
						master->AddTask(s10);
						master->AddTask(s11);
						master->AddTask(s12);
						master->AddTask(s13);
						master->AddTask(s14);
						master->AddTask(s15);
						master->AddTask(s16);

						//resolve graph and dependencies
						master->Build();

						//bind the master task to the server handler
						behaviorServer->SetMaster(master);
						int start = time(NULL);
						//execute the master task
						behaviorServer->ExecuteMaster(server.GetConnectionManager());
						std::cout << "Timespan : "<< (time(NULL)-start)<< std::endl;
				 }

				if (input=="execRandomNumber")
				 {
					 	GridSlaveTaskRandomNumber* s1 = new GridSlaveTaskRandomNumber("1");
						GridSlaveTaskRandomNumber* s2 = new GridSlaveTaskRandomNumber("2");
						GridSlaveTaskRandomNumber* s3 = new GridSlaveTaskRandomNumber("3");
						GridSlaveTaskRandomNumber* s4 = new GridSlaveTaskRandomNumber("4");
						GridSlaveTaskRandomNumber* s5 = new GridSlaveTaskRandomNumber("5");
						GridSlaveTaskRandomNumber* s6 = new GridSlaveTaskRandomNumber("6");
						GridSlaveTaskRandomNumber* s7 = new GridSlaveTaskRandomNumber("7");
						GridSlaveTaskRandomNumber* s8 = new GridSlaveTaskRandomNumber("8");
						GridSlaveTaskRandomNumber* s9 = new GridSlaveTaskRandomNumber("9");
						GridSlaveTaskRandomNumber* s10 = new GridSlaveTaskRandomNumber("10");
						GridSlaveTaskRandomNumber* s11 = new GridSlaveTaskRandomNumber("11");
						GridSlaveTaskRandomNumber* s12 = new GridSlaveTaskRandomNumber("12");
						GridSlaveTaskRandomNumber* s13 = new GridSlaveTaskRandomNumber("13");
						GridSlaveTaskRandomNumber* s14 = new GridSlaveTaskRandomNumber("14");
						GridSlaveTaskRandomNumber* s15 = new GridSlaveTaskRandomNumber("15");
						GridSlaveTaskRandomNumber* s16 = new GridSlaveTaskRandomNumber("16");

						s5->BindTaskCompleted(s2)<=500000; 
						s2->BindTaskCompleted(s3)<=500000;
						s4->BindTaskCompleted(s9)<=500000; 
						s3->BindTaskCompleted(s7)<=500000;
						s6->BindTaskCompleted(s2)<=500000;
						s1->BindTaskCompleted(s3)<=500000;

						s9->BindTaskCompleted(s12)<=500000;
						s10->BindTaskCompleted(s9)<=500000;
						s11->BindTaskCompleted(s4)<=500000;
						s8->BindTaskCompleted(s4)<=500000;

						s13->BindTaskCompleted(s14)<=500000;
						s14->BindTaskCompleted(s15)<=500000;
						s16->BindTaskCompleted(s15)<=500000;

						master = new GridMasterTask();
						master->AddTask(s1);
						master->AddTask(s2);
						master->AddTask(s3);
						master->AddTask(s4);
						master->AddTask(s5);
						master->AddTask(s6);
						master->AddTask(s7);
						master->AddTask(s8);
						master->AddTask(s9);
						master->AddTask(s10);
						master->AddTask(s11);
						master->AddTask(s12);
						master->AddTask(s13);
						master->AddTask(s14);
						master->AddTask(s15);
						master->AddTask(s16);

						master->Build();
						behaviorServer->SetMaster(master);
						int start = time(NULL);
						behaviorServer->ExecuteMaster(server.GetConnectionManager());
						std::cout << "Timespan : "<< (time(NULL)-start)<< std::endl;
				 }

				 if (input=="execReturnOne")
				 {

						GridSlaveTaskReturnOne* s1 = new GridSlaveTaskReturnOne("1");
						GridSlaveTaskReturnOne* s2 = new GridSlaveTaskReturnOne("2");
						GridSlaveTaskReturnOne* s3 = new GridSlaveTaskReturnOne("3");
						GridSlaveTaskReturnOne* s4 = new GridSlaveTaskReturnOne("4");
						GridSlaveTaskReturnOne* s5 = new GridSlaveTaskReturnOne("5");
						GridSlaveTaskReturnOne* s6 = new GridSlaveTaskReturnOne("6");
						GridSlaveTaskReturnOne* s7 = new GridSlaveTaskReturnOne("7");
						GridSlaveTaskReturnOne* s8 = new GridSlaveTaskReturnOne("8");
						GridSlaveTaskReturnOne* s9 = new GridSlaveTaskReturnOne("9");
						GridSlaveTaskReturnOne* s10 = new GridSlaveTaskReturnOne("10");
						GridSlaveTaskReturnOne* s11 = new GridSlaveTaskReturnOne("11");
						GridSlaveTaskReturnOne* s12 = new GridSlaveTaskReturnOne("12");
						GridSlaveTaskReturnOne* s13 = new GridSlaveTaskReturnOne("13");
						GridSlaveTaskReturnOne* s14 = new GridSlaveTaskReturnOne("14");
						GridSlaveTaskReturnOne* s15 = new GridSlaveTaskReturnOne("15");
						GridSlaveTaskReturnOne* s16 = new GridSlaveTaskReturnOne("16");

						s5->BindTaskCompleted(s2)<=500000; 
						s2->BindTaskCompleted(s3)<=500000;
						s4->BindTaskCompleted(s9)<=500000; 
						s3->BindTaskCompleted(s7)<=500000;
						s6->BindTaskCompleted(s2)<=500000;
						s1->BindTaskCompleted(s3)<=500000;

						s9->BindTaskCompleted(s12)<=500000;
						s10->BindTaskCompleted(s9)<=500000;
						s11->BindTaskCompleted(s4)<=500000;
						s8->BindTaskCompleted(s4)<=500000;

						s13->BindTaskCompleted(s14)<=500000;
						s14->BindTaskCompleted(s15)<=500000;
						s16->BindTaskCompleted(s15)<=500000;

						master = new GridMasterTask();
						master->AddTask(s1);
						master->AddTask(s2);
						master->AddTask(s3);
						master->AddTask(s4);
						master->AddTask(s5);
						master->AddTask(s6);
						master->AddTask(s7);
						master->AddTask(s8);
						master->AddTask(s9);
						master->AddTask(s10);
						master->AddTask(s11);
						master->AddTask(s12);
						master->AddTask(s13);
						master->AddTask(s14);
						master->AddTask(s15);
						master->AddTask(s16);

						master->Build();
						behaviorServer->SetMaster(master);
						int start = time(NULL);
						behaviorServer->ExecuteMaster(server.GetConnectionManager());
						std::cout << "Timespan : "<< (time(NULL)-start)<< std::endl;				
			}

			if (input=="printMaster")
			{
				std::cout<<"Results:"<<std::endl;
				for (std::vector<AbstractGridSlaveTask*>::iterator vi = master->GetTasks()->begin(); vi != master->GetTasks()->end(); vi++)
				{
					switch ((*vi)->GetTaskType())
					{
					case VALUE_TYPE::VALUE_TYPE_FLOAT:
						std::cout<< *(*vi)->GetName() << "::"<< (*(*vi)->GetResult()->GetResult<float>())<< std::endl;
						break;
					case VALUE_TYPE::VALUE_TYPE_INT32:
						std::cout<< *(*vi)->GetName() << "::"<< (*(*vi)->GetResult()->GetResult<int>())<< std::endl;
						break;
					case VALUE_TYPE::VALUE_TYPE_STRING:
						std::cout<< *(*vi)->GetName() << "::"<< (*(*vi)->GetResult()->GetResult<std::string>())<< std::endl;
						break;
					}

				}
			}



		}


	return 0;
}




